Skip to content

feat: DH-21757: WidgetPlugin support in deephaven.ui#1341

Open
mofojed wants to merge 37 commits into
deephaven:mainfrom
mofojed:DH-21757-resolve-deephaven.ui-widget-plugin
Open

feat: DH-21757: WidgetPlugin support in deephaven.ui#1341
mofojed wants to merge 37 commits into
deephaven:mainfrom
mofojed:DH-21757-resolve-deephaven.ui-widget-plugin

Conversation

@mofojed
Copy link
Copy Markdown
Member

@mofojed mofojed commented Apr 27, 2026

  • WidgetPlugin just registers directly
    • Allows for nested ui.resolve deephaven.ui components
  • Still maintain DashboardPlugin to handle legacy behaviour
  • Works with the ui_home_screen, nested dashboards, etc
  • Styling a little bit different (ui.panel is automatically wrapped in a nested dashboard rather than opening up panels in the existing dashboard like before)
    • Keeps all components contained to a panel, rather than mixing with other components in the same dashboard
  • Dashboard now has a show_headers option that can be set to False to not show headers on a dashboard. Useful if you're doing a homescreen type dashboard

mofojed added 12 commits April 27, 2026 09:40
- Needs deephaven/web-client-ui#2648
- WidgetPlugin just registers directly
  - Allows for nested ui.resolve deephaven.ui components
- Still maintain DashboardPlugin to handle legacy behaviour
- Works with the ui_home_screen, nested dashboards, etc
- Styling a little bit different (ui.panel is automatically wrapped in a nested dashboard rather than opening up panels in the existing dashboard like before)
- Dashboard now has a `show_headers` option that can be set to False to not show headers on a dashboard. Useful if you're doing a homescreen type dashboard
- Add moduleNameMapper in jest.config.cjs to resolve React 18 from the
  plugin's local node_modules, fixing dual-React-instance errors
- Mock usePersistentState in @deephaven/plugin mock to avoid FiberProvider
  dependency in tests
- Update DocumentHandler test to reflect new behavior where non-layout
  children are rendered directly without ReactPanel wrapping
- Wrap bare (non-layout) widget children in DefaultPanelContent so they
  receive padding and surface widget loading/error states (fixes the
  ui_boom_counter error overlay not appearing after the WidgetPlugin
  refactor).
- Add a styles.scss rule that strips the outer ReactPanel padding when
  its only child is a .dh-nested-dashboard, eliminating the duplicate
  padding around nested dashboards (e.g. ui_deeply_nested_dashboard).
- There's an issue here - when the ui.dashboard is the othermost thing, it should just take over the outer dashboard. Right now it's embeddign in. Need to fix that.
When a deephaven.ui widget is a single ui.panel hosted by the core
WidgetPanel (e.g. opened via the WidgetPlugin in a code studio or in
the embed widget scenario), render the panel's children inline using
DefaultPanelContent instead of opening another GoldenLayout panel.
Previously this produced a panel tab nested inside another panel tab.

DefaultPanelContent now forwards the same View/Flex props that
ReactPanel accepts so the user's ui.panel styling (padding, direction,
gap, etc.) is preserved when rendered inline, and applies the
dh-react-panel/dh-inner-react-panel class names so existing CSS rules
(grid/chart padding strip, etc.) still apply.

Also scope the nested-dashboard padding rule to .dh-react-panel so the
outer WidgetPanel does not add extra padding around a top-level
ui.dashboard in the embed widget scenario.
@mofojed mofojed self-assigned this Apr 27, 2026
@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

- now we don't have padding on the dashboard in the embed widget app scenario
@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@mofojed mofojed marked this pull request as ready for review April 29, 2026 15:36
@mofojed mofojed requested review from a team and removed request for a team April 29, 2026 15:36
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

ui docs preview (Available for 14 days)

margaretkennedy
margaretkennedy previously approved these changes May 7, 2026
Copy link
Copy Markdown
Contributor

@margaretkennedy margaretkennedy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs look good

@mofojed mofojed requested a review from dsmmcken May 8, 2026 13:44
Copy link
Copy Markdown
Contributor

@dsmmcken dsmmcken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all the other e2e changes expected?

Comment thread plugins/ui/docs/components/dashboard.md Outdated
"Value=i%2==0 ? `A` : `B`",
"Row=i",
]
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't use a timetable in e2e tests, you don't want anything ticking.

Though it doesn't look like the e2e tests display this, on screen. I think you should still switch it over so agents to follow it as a pattern.

Co-authored-by: Don <dsmmcken@gmail.com>
@mofojed
Copy link
Copy Markdown
Member Author

mofojed commented May 11, 2026

Adding @dgodinez-dh as the primary reviewer as he'll have more cycles this week than @vbabich

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@mofojed
Copy link
Copy Markdown
Member Author

mofojed commented May 11, 2026

@dsmmcken related to the other e2e changes:

  • ui_embed_widget.spec.ts-snapshots: Multi-panel widget: Before, when opening multiple panels ad hoc from a @ui.component, e.g.:
@ui.component
def ui_multi_panel_component():
    return [
        ui.panel(ui.button("Hello"), title="foo"),
        ui.panel(ui.text("World"), title="bar"),
    ]

we'd open them as a stack. This was inconsistent with how they were when it was displayed within a dashboard, e.g.

d = ui.dashboard([
    ui.panel(ui.button("Hello"), title="foo"),
    ui.panel(ui.text("World"), title="bar"),
])

Now opening a multi-panel component opens it in a nested dashboard, and the behaviour is consistent.

  • ui_nested_dashboard.spec.ts-snapshots: Removed the Close button from panels in a nested dashboard. Panels are controlled programmatically, and closing one can result in odd behaviour; user can't bring it back, it may re-appear randomly if the panel re-renders in the dashboard. If they don't want to see it, it can be stacked behind other panels.
  • ui.spec.ts-snapshots: Looks like I'm including the panel tab in the screenshot. I don't need to do that, I can clean that up.

// We may need to check if we need to close this widget if all panels are closed
const [isPanelsDirty, setPanelsDirty] = useState(false);

const id = useMemo(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks to me like this id is only used for debug logging? It might be more useful to add as much info to the id as is defined (e.g. id-name-type if it has all three).

uri?: UriVariableDescriptor;
};

export function UIComponent(props: UIComponentProps): JSX.Element | null {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a comment explaining UIComponent.


type UIWidgetProps = WidgetComponentProps<dh.Widget>;

export function UIWidget(props: UIWidgetProps): JSX.Element | null {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also have a comment explaining UIWidget.

Comment thread plugins/ui/src/js/src/UIWidgetPlugin.ts Outdated
import PortalPanel from './layout/PortalPanel';
import UIWidget from './UIWidget';

export const UIWidgetPlugin: WidgetPlugin<dh.Widget> = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also have a comment explaining UIWidgetPlugin.

Comment thread plugins/ui/src/js/src/UIComponent.tsx Outdated
// eslint-disable-next-line react/jsx-no-useless-fragment
<></>
),
// We only want to update this callback when the descriptor changes, not
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we update this callback as the return value never changes? I can see that we do it intentionally. Is it to trigger an update in WidgetHandler when the descriptor changes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I re-wired this and it shouldn't need to change on the descriptor anymore.

- Use the content of the panel instead of the full dashboard
@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@mofojed
Copy link
Copy Markdown
Member Author

mofojed commented May 11, 2026

@dsmmcken ui.spec.ts-snapshots: I have it opening the ui_render_all from the embed widget screen, rather than the main app; because dashboards now open as nested dashboards (within a panel in the Code Studio). Because of that, it's a slightly different height (because there's no dashboards listed across the top from the embed widget view).
On the Enterprise side, I think this would be desirable when creating dashboards from a code studio; your console input isn't hidden in another tab then, and you can easily try running edits to your dashboard.
Architectural it's simpler, as we don't need to wait for the component to load and then open a dashboard while closing the panel. (Opening the widget triggers opening a panel, which then loads the plugin and renders the dashboard in that panel - plugin needs to close that panel and open a new dashboard tab, which has hacks for the Code Studio keeping track of them, etc).
Do we still want that behaviour of dashboards created/opened in a Code Studio always open in a new dashboard tab?
On a related note - should dashboards be visible in the Panels menu? With nested dashboards there's no reason user's can't create an ad hoc dashboard with a bunch of other dashboards added to it.

@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

@mofojed mofojed requested review from dgodinez-dh and dsmmcken May 12, 2026 14:26
dgodinez-dh
dgodinez-dh previously approved these changes May 12, 2026
Copy link
Copy Markdown
Contributor

@dgodinez-dh dgodinez-dh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good. Looks like there is a failing test though.

- These weren't actually an issue the issue I was trying to fix, but the type errors I was getting in CI don't make sense: https://github.com/deephaven/deephaven-plugins/actions/runs/25740228037/job/75588279678?pr=1341
  - References REACT_PANEL_VISIBLE not being a valid symbol in ui_table.spec.ts, but that's not used anywhere in that file
  - Pushing this fix to see if it kicks CI into behaving
@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

Copy link
Copy Markdown
Contributor

@margaretkennedy margaretkennedy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs LGTM

…ards

- So we can still open widgets as dashboards from code studios
@github-actions
Copy link
Copy Markdown

ui docs preview (Available for 14 days)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants